#include <nlohmann/json.hpp>
#include "helper.hpp"
#include <Algorithm/CurveFitting/sdm.h>
#include <Algorithm/CurveFitting/pdm.h>

using namespace shermit;
using namespace shermit::fitting::curve;
using json = nlohmann::json;


int main(int argc, char** argv) {
	std::ifstream f(argv[1]);
	std::stringstream buf;
	buf << f.rdbuf();
	f.close();
	json config = json::parse(buf.str());
	auto&& pts = readVecs<double>(config["pts"]);
	auto&& cpts = readVecs<double>(config["control_pts"]);
	//double half_length = config["half_length"];
	double half_length = 0.0;
	int spr = config["sample_per_range"];
	auto solver_type = config["solver"];
	int max_iter_projection = config["max_iter_projection"];
	int max_iter_solver = config["max_iter_solver"];
	double errot_target = config["errot_target"];

	CubicBSplineCurve<double, DeviceType::CPU> curve;
	if (solver_type == "SDM") {
		auto solver = CudaSDMSolverLU64(pts, cpts, max_iter_solver, max_iter_projection, spr, half_length);
		solver.solve(errot_target, DistanceMetrics::SDM);
		curve = solver.getHostCurve();
	}
	else if (solver_type == "TDM") {
		auto solver = CudaSDMSolverLU64(pts, cpts, max_iter_solver, max_iter_projection, spr, half_length);
		solver.solve(errot_target, DistanceMetrics::TDM);
		curve = solver.getHostCurve();
	}
	else if (solver_type == "PDM") {
		auto solver = CudaPDMSolverLU64(pts, cpts, max_iter_solver, max_iter_projection, spr, half_length);
		solver.solve(errot_target);
		curve = solver.getHostCurve();
	}
		
	// print final control pts
	printf("control points:\n");
	printf("%d\n", curve.nControlPts());
	for (int i = 0; i < curve.nControlPts(); ++i) {
		auto pt = curve.getControlPts()[i];
		printf("%lf %lf\n", pt.x, pt.y);
	}
	auto& viewer = BSplineCurveViewer::getInstance();
	viewer.setInitWindowTitle("BSpline Curve");
	viewer.setWindowSize(1600, 900);
	viewer.setSampleFrequency(50);
	viewer.setBSplineCurve(curve);
	viewer.scale(500);
	viewer.initialize(argc, argv);
	viewer.tick();
	viewer.finalize();

	return 0;
}
